package com.casic.ops.service.impl.pipeline;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.casic.ops.consts.app.PipelineDetailStatus;
import com.casic.ops.consts.app.PipelineStatus;
import com.casic.ops.dao.pipeline.PipelineDAO;
import com.casic.ops.dao.pipeline.PipelineLoggerDAO;
import com.casic.ops.dao.pipeline.PipelineNodeLoggerDAO;
import com.casic.ops.entity.domain.ApplicationPipelineTaskDO;
import com.casic.ops.entity.domain.ApplicationPipelineTaskDetailDO;
import com.casic.ops.entity.domain.pipeline.PipelineDO;
import com.casic.ops.entity.domain.pipeline.PipelineLoggerDO;
import com.casic.ops.entity.domain.pipeline.PipelineNodeLoggerDO;
import com.casic.ops.entity.dto.ApplicationPipelineTaskStatisticsDTO;
import com.casic.ops.entity.dto.pipeline.PipelineLoggerDTO;
import com.casic.ops.entity.dto.pipeline.datastructure.graph.Graph;
import com.casic.ops.entity.dto.pipeline.datastructure.graph.Nodes;
import com.casic.ops.entity.dto.pipeline.datastructure.node.PipelineNodeConfigInfo;
import com.casic.ops.entity.request.pipeline.PipelineLoggerPageRequest;
import com.casic.ops.entity.request.pipeline.PipelineLoggerRequest;
import com.casic.ops.entity.vo.*;
import com.casic.ops.entity.vo.pipeline.*;
import com.casic.ops.entity.vo.pipeline.response.MultiResponse;
import com.casic.ops.entity.vo.pipeline.response.PageResponse;
import com.casic.ops.entity.vo.pipeline.response.Response;
import com.casic.ops.entity.vo.pipeline.response.SingleResponse;
import com.casic.ops.runner.pipeline.nodeconfiginfo.StartExecutableNodeConfigInfo;
import com.casic.ops.service.api.pipeline.PipelineLoggerService;
import com.casic.ops.service.api.pipeline.PipelineNodeInfoService;
import com.casic.ops.utils.Utils;
import com.casic.ops.utils.pipeline.PipelineLoggerConvertor;
import com.orion.utils.Arrays1;
import com.orion.utils.collect.Lists;
import com.orion.utils.time.Dates;
import org.apache.catalina.Pipeline;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class PipelineLoggerServiceImpl implements PipelineLoggerService {
    public PipelineLoggerServiceImpl() {
        super();
    }

    @Resource
    private PipelineLoggerDAO pipelineLoggerDAO;

    @Resource
    private PipelineNodeLoggerDAO pipelineNodeLoggerDAO;

    @Resource
    private PipelineNodeInfoService pipelineNodeInfoService;

    @Resource
    private PipelineDAO pipelineDAO;

    @Resource
    private PipelineLoggerConvertor pipelineLoggerConvertor;


    @Override
    public Response update(PipelineLoggerRequest pipelineLoggerRequest) {
        int result=pipelineLoggerDAO.updateById(pipelineLoggerConvertor.toDO(pipelineLoggerRequest.getPipelineExecuteLoggerDTO()));
        if (result==0){
            return Response.error("更新失败");
        }else{
            return Response.success();
        }

    }

    @Override
    public Response delete(Long[] ids) {
        /**
         * 删除为逻辑删除，0为删除，1为未删除
         */
        for(Long id:ids){
            PipelineLoggerDO pipelineLoggerDO=pipelineLoggerDAO.selectById(id);
            if(pipelineLoggerDO!=null){
            pipelineLoggerDO.setDeleted("0");
            pipelineLoggerDAO.updateById(pipelineLoggerDO);
            }
        }
        return Response.success();
    }

    @Override
    public Response deleteOne(long id) {
        /**
         * 逻辑删除，0为已删除，1为未删除
         */
//        PipelineLoggerDO pipelineLoggerDO=pipelineLoggerDAO.selectById(id);
//        if(pipelineLoggerDO!=null){
//            pipelineLoggerDO.setDeleted("0");
//            pipelineLoggerDAO.updateById(pipelineLoggerDO);
//        }
        //先真删除，不知道咋的，配置的为ignore的更新逻辑没生效，然后就暂时无法通过更新来逻辑删除
        pipelineLoggerDAO.deleteById(id);
        return Response.success();
    }

    @Override
    public SingleResponse<PipelineLoggerDTO> getById(long id) {
        PipelineLoggerDO pipelineLoggerDO=pipelineLoggerDAO.selectById(id);
        return SingleResponse.of(pipelineLoggerConvertor.toDTO(pipelineLoggerDO));
    }

    @Override
    public MultiResponse<PipelineLoggerDTO> list(String pipelineUuid) {
        QueryWrapper<PipelineLoggerDO> qw=new QueryWrapper<>();
        if(pipelineUuid!=null){
            qw.eq("pipeline_uuid",pipelineUuid);
        }
        qw.orderByDesc("gmt_create");
        List<PipelineLoggerDO> pipelineLoggerDOList=pipelineLoggerDAO.selectList(qw);
        List<PipelineLoggerDTO> pipelineLoggerDTOList=pipelineLoggerConvertor.toDTOList(pipelineLoggerDOList);
        return MultiResponse.of(pipelineLoggerDTOList);
    }

    @Override
    public PageResponse<PipelineLoggerDTO> page(PipelineLoggerPageRequest request) {
        QueryWrapper<PipelineLoggerDO> qw=new QueryWrapper<>();
        String pipelineUuid= request.getPipelineUuid();
        if(pipelineUuid!=null){
            qw.eq("pipeline_uuid",pipelineUuid);
        }
        qw.eq("deleted","1");
        qw.orderByDesc("gmt_create");
        /**
         * 获取总数量并保存
         */
        Integer count=pipelineLoggerDAO.selectCount(qw);
        PageResponse<PipelineLoggerDTO> response=new PageResponse<>();
        response.setTotalCount(count);
        response.setPageIndex(request.getPageIndex());
        response.setPageSize(request.getPageSize());
        /**
         * 查询一个Page记录并保存返回
         */
        Page<PipelineLoggerDO> page=new Page<>(request.getPageIndex(), request.getPageSize());
        IPage<PipelineLoggerDO> ipage=pipelineLoggerDAO.selectPage(page,qw);
        List<PipelineLoggerDO> records=ipage.getRecords();
        List<PipelineLoggerDTO> pipelineLoggerDTOList=pipelineLoggerConvertor.toDTOList(records);
        response.setData(pipelineLoggerDTOList);
        return response;
    }

    @Override
    public void updateByLoggerDO(PipelineLoggerDO loggerDO) {
        QueryWrapper<PipelineLoggerDO> qw=new QueryWrapper<>();
        qw.eq("uuid",loggerDO.getUuid());
        pipelineLoggerDAO.update(loggerDO,qw);
    }

    @Override
    public void add(PipelineLoggerDO loggerDO) {
        pipelineLoggerDAO.insert(loggerDO);
    }

    @Override
    public Response pipelineLoggerStatisticView(String pipelineUuid) {
        QueryWrapper<PipelineDO> qw=new QueryWrapper<>();
        qw.eq("uuid",pipelineUuid);
        PipelineDO pipelineDO=pipelineDAO.selectOne(qw);
        if(pipelineDO==null){
            return Response.success("该流水线不存在");
        }
        String piplineName=pipelineDO.getPipelineName();
        // 查询最近10次的执行记录 进行中/成功/失败
        LambdaQueryWrapper<PipelineLoggerDO> pipelineLoggerWrapper = new LambdaQueryWrapper<PipelineLoggerDO>()
                .eq(PipelineLoggerDO::getPipelineUuid, pipelineUuid)
                .in(PipelineLoggerDO::getFinalStatus,"成功","失败")
                .orderByDesc(PipelineLoggerDO::getId)
                .last("LIMIT 10");
        List<PipelineLoggerDO> pipelineLoggerDOList=pipelineLoggerDAO.selectList(pipelineLoggerWrapper);
        if(pipelineLoggerDOList.isEmpty()){
            return SingleResponse.of(null);
        }
        //封装数据
        PipelineStatisticsViewVO view = new PipelineStatisticsViewVO();
        String successStatus="成功";
        // 计算最近十次成功执行平均耗时
        long avgUsed = (long) pipelineLoggerDOList.stream()
                .filter(s ->successStatus.equals(s.getFinalStatus()))
                .filter(s -> s.getExecuteStartTime() != null && s.getExecuteEndTime() != null)
                .mapToLong(s -> s.getExecuteEndTime().getTime() - s.getExecuteStartTime().getTime())
                .average()
                .orElse(0);
        view.setAvgUsed(avgUsed);
        view.setAvgUsedInterval(Utils.interval(avgUsed));
        //获取PipelineLoggerUuid集合
        List<Long> pipelineLoggerUuidList = pipelineLoggerDOList.stream().map(PipelineLoggerDO::getUuid).collect(Collectors.toList());

        //查询pipelineNodeLoggerDO集合
        Wrapper<PipelineNodeLoggerDO> wrapper = new LambdaQueryWrapper<PipelineNodeLoggerDO>()
                .in(PipelineNodeLoggerDO::getPipelineLoggerUUid, pipelineLoggerUuidList);
        List<PipelineNodeLoggerDO> pipelineNodeLoggerDOList = pipelineNodeLoggerDAO.selectList(wrapper);

        // 设置流水线节点
        String pipelineContext=pipelineDO.getPipelineContext();
        Graph graph= JSON.parseObject(pipelineContext,Graph.class);
        List<Nodes> nodesList=graph.getNodes();
        //这里要去除结束节点
        List<PipelineStaticsNodeDetailVO>  details =
                nodesList.stream()
                        .filter(var->!var.getName().equals("END"))
                        .map(var -> PipelineStaticsNodeDetailVO.Nodes2pipelineStatisticsNodeDetailVO(var))
                        .collect(Collectors.toList());
        view.setDetails(details);

        //设置流水线记录
        List<PipelineStaticsLoggerVO> pipelineStaticsLoggerVOList=new ArrayList<>();
        for(PipelineLoggerDO loggerDO:pipelineLoggerDOList){
            PipelineStaticsLoggerVO pipelineStaticsLoggerVO=PipelineStaticsLoggerVO.pipelineLoggerDO2pipelineStatisticsLoggerVO(loggerDO);
            pipelineStaticsLoggerVO.setTitle(piplineName);
            pipelineStaticsLoggerVOList.add(pipelineStaticsLoggerVO);
        }
        //设置流水线记录的所有节点记录
        for(PipelineStaticsLoggerVO vo:pipelineStaticsLoggerVOList){
           List<PipelineStaticsticsNodeloggerVO> pipelineStaticsticsNodeloggerVOList= pipelineNodeLoggerDOList.stream()
                    .filter(s -> s.getPipelineLoggerUUid()==(vo.getUuid()))
                    .map(PipelineStaticsticsNodeloggerVO::PipelineNodeLoggerDo2PipelineStaticsticsNodeLoggerDo)
                    .collect(Collectors.toList());
           vo.setDetails(pipelineStaticsticsNodeloggerVOList);
        }
        //保存流水线执行记录
        view.setPipelineStaticsLoggerVOList(pipelineStaticsLoggerVOList);
        Integer successCode=Integer.valueOf(30);
        //设置流水线各个节点的平均用时
        for ( PipelineStaticsNodeDetailVO detail : details) {
            long actionAvgUsed = (long) pipelineStaticsLoggerVOList.stream()
                    .map(PipelineStaticsLoggerVO::getDetails)
                    .filter(Objects::nonNull)
                    .flatMap(Collection::stream)
                    .filter(Objects::nonNull)
                    .filter(s -> s.getNodeUuid().equals(detail.getNodeUuid()))
                    .filter(s -> successCode.equals(s.getStatus()))
                    .map(PipelineStaticsticsNodeloggerVO::getUsed)
                    .filter(Objects::nonNull)
                    .mapToLong(s -> s)
                    .average()
                    .orElse(0);
            detail.setAvgUsed(actionAvgUsed);
            detail.setAvgUsedInterval(Utils.interval(actionAvgUsed));
        }
        return SingleResponse.of(view);
    }

    @Override
    public SingleResponse<PipelineStaticsMetricsWrapperVO> pipelineLoggerStatisticMetrics(String pipelineUuid) {
        PipelineStaticsMetricsWrapperVO wrapper = new PipelineStaticsMetricsWrapperVO();
        DateFormat dateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Calendar calendar=Calendar.getInstance();
        String nowDate=dateFormat.format(calendar.getTime());
        calendar.set(Calendar.HOUR_OF_DAY,-24*7);
        String lastWeekDate=dateFormat.format(calendar.getTime());
        //获取一周之内的流水线执行记录
        QueryWrapper<PipelineLoggerDO> qw=new QueryWrapper<>();
        qw.ge("execute_start_time",lastWeekDate);
        qw.le("execute_start_time",nowDate);
        qw.eq("pipeline_uuid",pipelineUuid);
        List<PipelineLoggerDO> pipelineLoggerDoList=pipelineLoggerDAO.selectList(qw);
        PipelineStaticsticsMetricsVO pipelineStaticsticsMetricsVO=new PipelineStaticsticsMetricsVO();
        //获取一周之内的执行次数
        long execCount=pipelineLoggerDoList.stream().count();
        pipelineStaticsticsMetricsVO.setExecCount(execCount);
        //获取一周内的成功执行次数
        String successStatus="成功";
        long successCount=pipelineLoggerDoList.stream().filter(s->successStatus.equals(s.getFinalStatus())).count();
        pipelineStaticsticsMetricsVO.setSuccessCount(successCount);
        //获取一周内的失败执行次数
        long failureCount=execCount-successCount;
        pipelineStaticsticsMetricsVO.setFailureCount(failureCount);
        //获取平均用时
        long avgUsed = (long) pipelineLoggerDoList.stream()
                .filter(s -> successStatus.equals(s.getFinalStatus()))
                .filter(s -> s.getExecuteStartTime() != null && s.getExecuteEndTime() != null)
                .mapToLong(s -> s.getExecuteEndTime().getTime() - s.getExecuteStartTime().getTime())
                .average()
                .orElse(0);
        pipelineStaticsticsMetricsVO.setAvgUsed(avgUsed);
        pipelineStaticsticsMetricsVO.setAvgUsedInterval(Utils.interval(avgUsed));
        //封装数据
        PipelineStaticsMetricsWrapperVO wrapperVO=new PipelineStaticsMetricsWrapperVO();
        wrapperVO.setLately(pipelineStaticsticsMetricsVO);

        //获取所有流水线执行记录
        QueryWrapper<PipelineLoggerDO> qw2=new QueryWrapper<>();
        qw2.eq("pipeline_uuid",pipelineUuid);
        List<PipelineLoggerDO> pipelineLoggerDoList2=pipelineLoggerDAO.selectList(qw);
        PipelineStaticsticsMetricsVO pipelineStaticsticsMetricsVO2=new PipelineStaticsticsMetricsVO();
        //获取所有执行总数
        long execCount2=pipelineLoggerDoList.stream().count();
        pipelineStaticsticsMetricsVO2.setExecCount(execCount2);
        //获取所有执行成功次数
        long successCount2=pipelineLoggerDoList2.stream().filter(s->successStatus.equals(s.getFinalStatus())).count();
        pipelineStaticsticsMetricsVO2.setSuccessCount(successCount2);
        //获取所有成功执行次数
        long failureCount2=execCount-successCount;
        pipelineStaticsticsMetricsVO2.setFailureCount(failureCount2);
        //获取平均用时
        long avgUsed2 = (long) pipelineLoggerDoList2.stream()
                .filter(s -> successStatus.equals(s.getFinalStatus()))
                .filter(s -> s.getExecuteStartTime() != null && s.getExecuteEndTime() != null)
                .mapToLong(s -> s.getExecuteEndTime().getTime() - s.getExecuteStartTime().getTime())
                .average()
                .orElse(0);
        pipelineStaticsticsMetricsVO2.setAvgUsed(avgUsed);
        pipelineStaticsticsMetricsVO2.setAvgUsedInterval(Utils.interval(avgUsed));
        wrapperVO.setAll(pipelineStaticsticsMetricsVO2);
        return SingleResponse.of(wrapperVO);
    }

    @Override
    public SingleResponse<List<PipelineStaticsChartVO>> pipelineLoggerStatisticChart(String pipelineUuid) {
        //7天的日期数组
        Date[] chartDates = Dates.getIncrementDates(Dates.clearHms(), Calendar.DAY_OF_MONTH, -1, 7);
        Date rangeStartDate = Arrays1.last(chartDates);
        List<PipelineStaticsChartVO> pipelineStaticsChartVOS=new ArrayList<>();
        DateFormat dateFormat=new SimpleDateFormat("yyyy-MM-dd");
        //零时零分零秒
        String s1=" 00:00:00";
        //23时59分59秒
        String s2=" 23:59:59";
        String successStatus="成功";
        //获取一周内的执行记录统计数据
        for(Date date:chartDates){
            String day= dateFormat.format(date);
            PipelineStaticsChartVO vo=new PipelineStaticsChartVO();
            vo.setDate(day);
            QueryWrapper<PipelineLoggerDO> qw=new QueryWrapper<>();
            //获取某一天的执行，计算时间是零时零分零秒到23时59分59秒
            qw.ge("execute_start_time",day+s1);
            qw.le("execute_start_time",day+s2);
            qw.eq("pipeline_uuid",pipelineUuid);
            List<PipelineLoggerDO> pipelineLoggerDOList=pipelineLoggerDAO.selectList(qw);
            long executeCount=pipelineLoggerDOList.stream().count();
            vo.setExecCount(executeCount);
            long successCount=pipelineLoggerDOList.stream().filter(s->successStatus.equals(s.getFinalStatus())).count();
            vo.setSuccessCount(successCount);
            long failureCount=executeCount-successCount;
            vo.setFailureCount(failureCount);
            pipelineStaticsChartVOS.add(vo);
        }
        return SingleResponse.of(pipelineStaticsChartVOS);
    }

    @Override
    public Response getRecentlyHistory() {
        /**
         * 首页，先获取最新的4个最新执行记录
         */
        QueryWrapper<PipelineDO> qw=new QueryWrapper<>();
        qw.orderByDesc("gmt_create");
        qw.last("LIMIT 4");
        List<PipelineDO> pipelineDOList=pipelineDAO.selectList(qw);
        List<PipelineBuildHistoryVO> pipelineBuildHistoryVOS=new ArrayList<>();
        for(PipelineDO pipelineDO:pipelineDOList){
//            //查询最新的一条执行记录
//            QueryWrapper<PipelineLoggerDO> queryWrapper=new QueryWrapper<>();
//            queryWrapper.eq("pipeline_uuid",pipelineDO.getUuid());
//            queryWrapper.orderByAsc("execute_start_time");
//            queryWrapper.last("LIMIT 1");
//            PipelineLoggerDO pipelineLoggerDO=pipelineLoggerDAO.selectOne(queryWrapper);
            PipelineBuildHistoryVO vo=new PipelineBuildHistoryVO();
            vo.setPipelineName(pipelineDO.getPipelineName());
            vo.setPipelineUuid(pipelineDO.getUuid());
            Graph graph=JSON.parseObject(pipelineDO.getPipelineContext(),Graph.class);
            List<Nodes> nodesList=graph.getNodes().stream().filter(s->!s.getName().equals("END")).collect(Collectors.toList());
            Nodes endNode=graph.getNodes().stream().filter(s->s.getName().equals("END")).findFirst().get();
            nodesList.add(endNode);
            vo.setNodesList(nodesList);
            //获取开始节点的代码分支信息
            Nodes startNode=nodesList.stream().filter(s->s.getName().equals("START")).findFirst().get();
            PipelineNodeConfigInfo startNodeConfigInfo=pipelineNodeInfoService.selectByNodeUuid(startNode.getId());
            if(startNode!=null){
                StartExecutableNodeConfigInfo configInfo=JSON.parseObject(startNodeConfigInfo.getInfo(),StartExecutableNodeConfigInfo.class);
                String branch=configInfo.getBranch();
                vo.setBranch(branch);
            }else{
                vo.setBranch("暂未配置分支信息");
            }
            pipelineBuildHistoryVOS.add(vo);
        }
        DashBodrdBuildHistoryVO dashBodrdBuildHistoryVO=new DashBodrdBuildHistoryVO();
        dashBodrdBuildHistoryVO.setHistoryVOList(pipelineBuildHistoryVOS);
        return SingleResponse.of(dashBodrdBuildHistoryVO);
    }
}
